//
// Created on 2025/5/29.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "LinphoneManager.h"
#include "belle-sip/utils.h"
#include "linphone/enums/call-enums.h"
#include "log/ohos_log.h"
#include <belr/grammarbuilder.h>
#include <thread>
#include <uv.h>

const int CALL_CODE_ADD = 10000; // 区分通话中的code
bool incoming_call = false;
LinphoneCall *current_call = nullptr;
napi_ref LinphoneManager::callBack_ = nullptr;
napi_env LinphoneManager::env_ = nullptr;
int callStatusCode = -1;

extern MSFilterDesc ms_ohos_audio_enc_desc;
extern MSFilterDesc ms_ohos_audio_dec_desc;
extern MSSndCardDesc ohos_snd_card_desc;


void log_handler(const char *domain, BctbxLogLevel level, const char *message, va_list args) { LOGL(args, message); }

// 注册状态变化回调函数
void LinphoneManager::registration_state_changed(LinphoneCore *core, LinphoneAccount *account,
                                                 LinphoneRegistrationState state, const char *message) {
    switch (state) {
    case LinphoneRegistrationNone:
        LOGE("linphoneTag messageCallBack未初始化");
        break;
    case LinphoneRegistrationProgress:
        LOGE("linphoneTag messageCallBack正在注册...");
        break;
    case LinphoneRegistrationOk:
        LOGE("linphoneTag messageCallBack注册成功!");
        break;
    case LinphoneRegistrationCleared:
        LOGE("linphoneTag messageCallBack已注销");
        break;
    case LinphoneRegistrationFailed:
        LOGE("linphoneTag messageCallBack注册失败");
        break;
    default:
        LOGE("linphoneTag messageCallBack未知状态");
    }
    CallBackToArkts(state);
}
// 回调函数处理呼叫状态
void LinphoneManager::call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate,
                                         const char *msg) {
    current_call = call;
    callStatusCode = cstate;
    LOGE("linphoneTag2 call_state_changed code:%d", cstate);
    switch (cstate) {
    case LinphoneCallIncomingReceived:
        LOGE("linphoneTag2 通话已接通,来电号码: %s",
             linphone_address_get_username(linphone_call_get_remote_address(call)));
        incoming_call = true;
        break;
    case LinphoneCallStreamsRunning: {
        LOGE("linphoneTag2 通话中...");
        MSFactory *factory = linphone_core_get_ms_factory(lc);
        MSFilter *custom_filter = ms_factory_create_filter(factory, MS_OHOS_AUDIO_ENC);
        if (custom_filter) {
            // 获取音频流
            
//                LinphoneMediaStream *stream = linphone_call_get_media_stream(call, LinphoneMediaAudio);
//                if (stream) {
//                    // 获取当前音频处理链
//                    MSFilter *audio_chain = linphone_media_stream_get_filter(stream);
            //                    
//                    // 插入到发送链
//                    ms_filter_link(ms_filter_get_source(audio_chain), 0, custom_filter, 0);
//                    ms_filter_link(custom_filter, 0, ms_filter_get_sink(audio_chain), 0);
            //                    
//                    // 设置自定义参数
//                    my_audio_filter_set_param(custom_filter, 42);
            //                    
//                    printf("Custom audio filter activated!\n");
            
//                }
            // ms_filter_link  //ms_filter_get_sink
//             ms_filter_link(MSFilter *f1, int pin1, MSFilter *f2, int pin2)
        }
    }

    break;
    case LinphoneCallOutgoingInit:
        LOGE("linphoneTag2 正在发起呼叫...");
        break;
    case LinphoneCallOutgoingProgress:
        LOGE("linphoneTag2 呼叫进行中...");
        break;
    case LinphoneCallConnected:
        LOGE("linphoneTag2 通话已连接");
        break;
    case LinphoneCallEnd:
        LOGE("linphoneTag2 通话结束");
        if (current_call) {
            linphone_call_unref(current_call);
            current_call = nullptr;
        }
        break;
    case LinphoneCallError:
        LOGE("linphoneTag2 呼叫错误: %s", msg);
        if (current_call) {
            linphone_call_unref(current_call);
            current_call = nullptr;
        }
        break;
    default:
        break;
    }
    CallBackToArkts((CALL_CODE_ADD + cstate));
}

void LinphoneManager::CallBackToArkts(int code) {
    if (LinphoneManager::callBack_ && LinphoneManager::env_) {
        CallBack *requestCallback = new CallBack{
            .env_ = LinphoneManager::env_,
            .callbackRef = LinphoneManager::callBack_,
            .code = code,
        };
        uv_loop_s *loopMessage = nullptr;
        napi_get_uv_event_loop(LinphoneManager::env_, &loopMessage);
        if (loopMessage == nullptr) {
            return;
        }
        uv_work_t *work = new (std::nothrow) uv_work_t;
        if (work == nullptr) {
            return;
        }
        work->data = requestCallback;
        uv_queue_work(
            loopMessage, work, [](uv_work_t *work) {},
            [](uv_work_t *work, int status) {
                CallBack *requestCallback = (CallBack *)(work->data);
                napi_value callback = nullptr;
                napi_value ret = 0;
                napi_value sta;
                napi_create_int32(requestCallback->env_, requestCallback->code, &sta);
                napi_get_reference_value(requestCallback->env_, requestCallback->callbackRef, &callback);
                napi_value param[] = {sta};
                napi_call_function(requestCallback->env_, nullptr, callback, 1, param, &ret);
            });
    }
}

void LinphoneManager::ms_ohos_snd_card_register(MSFactory *factory) {
    ms_message("Registering OHOS virtual audio card...");
    // 注册自定义的 encoder/decoder
    ms_factory_register_filter(factory, &ms_ohos_audio_enc_desc);
    ms_factory_register_filter(factory, &ms_ohos_audio_dec_desc);

    // 创建并注册设备
    MSSndCard *card = ms_snd_card_new(&ohos_snd_card_desc);
    ms_snd_card_set_name(card, "OHOS Virtual Audio");

    MSSndCardManager *manager = ms_factory_get_snd_card_manager(factory);
    ms_snd_card_manager_add_card(manager, card);
}

void LinphoneManager::SetCallCallBack(napi_env env, napi_ref callBack) {
    callBack_ = std::move(callBack);
    env_ = env;
}

int LinphoneManager::login(std::string userName, std::string pwd, std::string ip, std::string path) {
    LOGE("linphoneTag 开始登录");
    if (!linphoneData) {
        linphoneData = std::make_shared<LinphoneManager::LinphoneData>();
    }
    userName_ = userName;
    pwd_ = pwd;
    ip_ = ip;
    path_ = path;
    std::thread t([userName, pwd, ip, path, this]() { this->handleLogin(); });
    t.detach();
    return 0;
}

void LinphoneManager::handleLogin() {
    belr::GrammarLoader::get().addPath(path_);
    linphone_factory_set_data_dir(linphone_factory_get(), path_.c_str());
    LinphoneCoreVTable vtable = {0};
    linphone_core_set_log_level(BCTBX_LOG_DEBUG);
    linphone_core_set_log_handler(log_handler);


    vtable.account_registration_state_changed = registration_state_changed;
    vtable.call_state_changed = call_state_changed;
    LinphoneCore *lc = linphone_core_new(&vtable, NULL, NULL, NULL);

    MSFactory *factory = linphone_core_get_ms_factory(lc);
    ms_ohos_snd_card_register(factory);

    bctbx_list_t *list = linphone_core_get_audio_devices(lc);
    int audio_devices_count = (int)bctbx_list_size(list);
    LOGE("%s: %d audio_devices_count: %d", __FUNCTION__, __LINE__, audio_devices_count);

    // 禁用默认音频设备（让自定义编码器处理）
    linphone_core_set_capture_device(lc, nullptr);
    linphone_core_set_playback_device(lc, nullptr);

    linphone_core_enable_video_capture(lc, TRUE);
    linphone_core_enable_video_display(lc, TRUE);

    this->linphoneData->lc = lc;
    // 配置认证信息
    LinphoneAuthInfo *auth_info =
        linphone_auth_info_new(userName_.c_str(), nullptr, pwd_.c_str(), nullptr, nullptr, nullptr);
    this->linphoneData->auth_info = auth_info;
    linphone_core_add_auth_info(lc, auth_info);

    std::string idenAddress = "sip:" + userName_ + "@" + ip_;
    LinphoneAddress *identity_addr = linphone_address_new(idenAddress.c_str());
    if (!identity_addr) {
        LOGE("linphoneTag 无效的Identity地址!");
        linphone_address_unref(identity_addr);
        return;
    }
    // LinphoneSipTransports
    std::string address = "sip:" + ip_ + ";transport=udp";
    LinphoneAddress *server_addr = linphone_address_new(address.c_str());
    if (!server_addr) {
        LOGE("linphoneTag 无效的服务器地址!");
        linphone_address_unref(identity_addr);
        return;
    }
    LinphoneAccountParams *account_params = linphone_account_params_new(nullptr, FALSE);
    linphone_account_params_set_identity_address(account_params, identity_addr);
    linphone_account_params_set_server_address(account_params, server_addr);
    linphone_account_params_enable_register(account_params, TRUE);

    LinphoneAccount *account = linphone_core_create_account(lc, account_params);
    this->linphoneData->account = account;
    if (!account) {
        LOGE("linphoneTag 账户添加失败!");
        return;
    }
    int rv = linphone_core_add_account(lc, account);
    linphone_core_set_default_account(lc, account);
    LOGE("linphoneTag 账户添加linphone_core_add_account %d", rv);
    // 释放临时对象
    linphone_address_unref(identity_addr);
    linphone_address_unref(server_addr);
    linphone_account_params_unref(account_params);
    // 消除杂音
    linphone_core_enable_echo_cancellation(this->linphoneData->lc, FALSE);
    while (true) {
        if (callStatusCode == LinphoneCallEnd || callStatusCode == LinphoneCallError) { // 通话结束的时候，跳出
            callStatusCode = -1;
            break;
        }
        LOGE("linphoneTag callStatusCode %d", callStatusCode);
        linphone_core_iterate(this->linphoneData->lc);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        LinphoneRegistrationState state = linphone_account_get_state(this->linphoneData->account);
        if (state != LinphoneRegistrationOk) {
            LOGE("linphoneTag 获取状态linphone_account_get_state %d", state);
        }
    }
}

void LinphoneManager::accept_call() {
    if (!linphoneData) {
        return;
    }
    if (current_call && incoming_call) {
        LOGE("linphoneTag 正在接听来电...");
        linphone_call_accept(current_call);
        incoming_call = false;
    }
}
void LinphoneManager::handUp_call() {
    if (current_call) {
        LOGE("linphoneTag handUp_call...");
        callStatusCode = LinphoneCallEnd;
        linphone_call_terminate(current_call);
        incoming_call = false;
    }
}

void LinphoneManager::make_call(std::string address) {
    if (!linphoneData) {
        return;
    }
    std::thread t([address, this]() {
        // 发起呼叫（替换目标号码）
        LOGE("linphoneTag 11拨打电话开始%d", linphone_core_video_enabled(this->linphoneData->lc));
        LinphoneCall *call = linphone_core_invite(this->linphoneData->lc, address.c_str());
        if (!call) {
            LOGE("linphoneTag 呼叫初始化失败");
            return;
        }
    });
    t.detach();
}
void LinphoneManager::setRemoteSurfaceId(std::string surfaceId) { 
    surfaceId_ = surfaceId; 
}

void LinphoneManager::destroy() {
    // 清理资源
    linphone_core_remove_account(this->linphoneData->lc, this->linphoneData->account);
    linphone_account_unref(this->linphoneData->account);
    linphone_core_unref(this->linphoneData->lc);
    linphone_auth_info_unref(this->linphoneData->auth_info);
}